﻿// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证（版本 2.0）进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动！任何基于本项目二次开发而产生的一切法律纠纷和责任，我们不承担任何责任！

using COSXML.Network;
using RestSharp;
using System.Security.Cryptography;

namespace Sinc.ERP.Application.Service.ChineMobile;

internal class ChineMobileService
{
    public ChineMobileService()
    { }

    private readonly string EncryptKey = null;
    public ChineMobileService(string encryptKey)
    {
        this.EncryptKey = encryptKey;
    }

    #region 自动激活卡片
    /// <summary>
    /// 自动激活卡片
    /// </summary>
    /// <param name="fullCode"></param>
    /// <param name="passcode"></param>
    /// <returns></returns>
    public async Task<(bool, string)> Activate(string fullCode, string passcode)
    {
        {
            var response = await this.VerifyAsync(fullCode, passcode);
            if (response.IsError())
                return (false, response.GetErrorMessage());
        }

        string msisdn = null;
        {
            var response = await this.GetCardInformationAsync(fullCode);
            if (response.IsError())
                return (false, response.GetErrorMessage());

            msisdn = response.Result.Body.MSISDN;
        }

        {
            var response = await this.GetUssdSmsCodeAsync(fullCode, msisdn);
            if (response.IsError())
                return (false, response.GetErrorMessage());
        }

        return (true, null);
    }
    #endregion

    #region 验证卡密是否有效
    /// <summary>
    /// 验证卡密是否有效
    /// </summary>
    /// <param name="fullCode"></param>
    /// <param name="passcode"></param>
    /// <returns></returns>
    public async Task<VerifySimPasscodeResponse> VerifyAsync(string fullCode, string passcode)
    {
        var request = new VerifySimPasscodeRequest(fullCode, passcode);
        return await this.SendRequest<VerifySimPasscodeResponse>(request, "edas/sim/verifySimWithPasscode", $"{fullCode}_{nameof(VerifyAsync)}");
    }
    #endregion

    #region 获取卡片信息
    /// <summary>
    /// 获取卡片信息
    /// </summary>
    /// <param name="fullCode"></param>
    /// <returns></returns>
    public async Task<CardInformationResponse> GetCardInformationAsync(string fullCode)
    {
        var request = new CardInformationRequest(fullCode);
        return await this.SendRequest<CardInformationResponse>(request, "portal/realName/proxy/getCardInformation", $"{fullCode}_{nameof(GetCardInformationAsync)}");
    }
    #endregion

    #region 激活卡片
    /// <summary>
    /// 激活卡片
    /// </summary>
    /// <param name="fullCode"></param>
    /// <param name="msisdn"></param>
    /// <returns></returns>
    public async Task<GetUssdSmsCodeResponse> GetUssdSmsCodeAsync(string fullCode, string msisdn)
    {
        var request = new GetUssdSmsCodeRequest(msisdn);
        return await this.SendRequest<GetUssdSmsCodeResponse>(request, "edas/realNameEnquiry/getUssdSmsCode", $"{fullCode}_{nameof(GetUssdSmsCodeAsync)}");
    }
    #endregion

    #region 发送请求
    private const CipherMode EncryptMode = CipherMode.ECB;
    /// <summary>
    /// 发送请求
    /// </summary>
    /// <typeparam name="TResponse"></typeparam>
    /// <param name="request"></param>
    /// <param name="url"></param>
    /// <param name="logKey"></param>
    /// <returns></returns>
    private async Task<TResponse> SendRequest<TResponse>(BaseRequest request, string url, string logKey = null) where TResponse : BaseResponse, new()
    {
        var response = new TResponse();
        if (!string.IsNullOrWhiteSpace(request?.ErrorMessage))
        {
            response.SetErrorMessage(request.ErrorMessage);
            return response;
        }

        var localVarPath = url.StartsWith("http") ? url : $"https://rnr.hk.chinamobile.com/mylink-rns/{(url.StartsWith("/") ? url.TrimStart("/") : url)}";
        var requestBody = JSON.Serialize(request);

        var client = new RestClient();
        var restRequest = new RestRequest(localVarPath, Method.Post);
        if (request.IsEncrypt)
        {
            requestBody = AESEncryption.Encrypt(requestBody, this.EncryptKey, mode: EncryptMode);
            restRequest.AddStringBody(requestBody, ContentType.Plain);
        }
        else
        {
            restRequest.AddJsonBody(requestBody);
        }
        restRequest.AddHeader("Content-Type", "application/json;charset=UTF-8");
        restRequest.AddHeader("Accept", "application/json, text/plain, */*");
        restRequest.AddHeader("Accept-Language", "sc");
        restRequest.AddHeader("Accept-Encoding", "gzip, deflate, br, zstd");
        restRequest.AddHeader("Connection", "keep-alive");
        restRequest.AddHeader("Origin", "https://rnr.hk.chinamobile.com");
        restRequest.AddHeader("Referer", "https://rnr.hk.chinamobile.com/realname/");
        restRequest.AddHeader("User-Agent", "Mozilla/5.0 (iPad; CPU OS 14_7_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Mobile/15E148 Safari/604.1");
        var restResponse = await client.ExecuteAsync(restRequest);

        EncryptResponse encryptResponse = null;
        if (logKey.IsNotEmpty())
        {
            var logBuilder = new StringBuilder();
            logBuilder.AppendLine(localVarPath);
            logBuilder.AppendLine();
            logBuilder.AppendLine();
            logBuilder.AppendLine("==============================请求信息===================================");
            logBuilder.AppendLine(requestBody);
            if (request.IsEncrypt)
            {
                logBuilder.AppendLine();
                logBuilder.AppendLine(JSON.Serialize(request));
            }
            logBuilder.AppendLine();
            restRequest.Parameters.Where(item => item.Type != ParameterType.RequestBody).ForEach(item => logBuilder.AppendLine($"{item.Name}:{item.Value}"));

            logBuilder.AppendLine();
            logBuilder.AppendLine();
            logBuilder.AppendLine("==============================返回信息===================================");
            logBuilder.AppendLine(restResponse.ErrorException?.ToString() ?? restResponse.Content);
            if (request.IsEncrypt && restResponse.ErrorException == null)
            {
                logBuilder.AppendLine();
                try
                {
                    encryptResponse = JSON.Deserialize<EncryptResponse>(restResponse.Content);
                    if (encryptResponse != null && encryptResponse.Encrypt)
                    {
                        var responseBody = AESEncryption.Decrypt(encryptResponse.Data, this.EncryptKey, mode: EncryptMode);
                        encryptResponse.Data = responseBody;
                        logBuilder.AppendLine(responseBody);
                    }
                }
                catch { }
            }
            logBuilder.AppendLine();
            restResponse.Headers.ToDictionary(x => x.Name, x => x.Value.ToString()).ForEach(item => logBuilder.AppendLine($"{item.Key}:{item.Value}"));

            var logFileName = $"{logKey}_{DateTime.Now:HHmmssffff}.txt";
            var logFilePath = Path.Combine(AppContext.BaseDirectory, "logs", "ChinaMobileLogs", logFileName);
            var logDirectory = Path.GetDirectoryName(logFilePath);
            if (!Directory.Exists(logDirectory))
                Directory.CreateDirectory(logDirectory);
            await File.WriteAllTextAsync(logFilePath, logBuilder.ToString());
        }

        if (restResponse.ErrorException != null)
        {
            response.SetErrorMessage(restResponse.ErrorException.Message);
            return response;
        }

        try
        {
            var responseBody = request.IsEncrypt ? encryptResponse.Data : restResponse.Content;
            response = JSON.Deserialize<TResponse>(responseBody);
        }
        catch (Exception ex)
        {
            response = new TResponse();
            response.SetErrorMessage($"解析API返回结果异常：{restResponse.Content}");
        }
        return response;
    }
    #endregion
}
